{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/tomasonjo/blogs/blob/master/lotr_graph_data_science_catalog/Cypher%20projection%20of%20the%20Graph%20Catalog%20feature%20on%20a%20Lord%20of%20the%20Rings%20network.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "* Updated to GDS 2.0 version\n",
        "* Link to original blog post: https://towardsdatascience.com/how-to-use-cypher-projection-in-neo4j-graph-data-science-library-on-a-lord-of-the-rings-social-b3459138c4f1"
      ],
      "metadata": {
        "id": "UCDl1zQhxjA6"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install neo4j"
      ],
      "metadata": {
        "id": "v5NVMOs8xuh3",
        "outputId": "6d5600c9-e9e6-4eb3-96e1-555ab88bf33f",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 1,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Collecting neo4j\n",
            "  Downloading neo4j-4.4.2.tar.gz (89 kB)\n",
            "\u001b[K     |████████████████████████████████| 89 kB 2.7 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pytz in /usr/local/lib/python3.7/dist-packages (from neo4j) (2018.9)\n",
            "Building wheels for collected packages: neo4j\n",
            "  Building wheel for neo4j (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for neo4j: filename=neo4j-4.4.2-py3-none-any.whl size=115365 sha256=3360555015b79a30c0fdb4eb00bc66b6254349351cee360aa68306c72de18675\n",
            "  Stored in directory: /root/.cache/pip/wheels/10/d6/28/95029d7f69690dbc3b93e4933197357987de34fbd44b50a0e4\n",
            "Successfully built neo4j\n",
            "Installing collected packages: neo4j\n",
            "Successfully installed neo4j-4.4.2\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "dKEx3tMNxgdH"
      },
      "outputs": [],
      "source": [
        "# Define Neo4j connections\n",
        "from neo4j import GraphDatabase\n",
        "host = 'bolt://3.235.2.228:7687'\n",
        "user = 'neo4j'\n",
        "password = 'seats-drunks-carbon'\n",
        "driver = GraphDatabase.driver(host,auth=(user, password))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "nngbaZV-xgdL"
      },
      "outputs": [],
      "source": [
        "# Import libraries\n",
        "import pandas as pd\n",
        "\n",
        "def read_query(query):\n",
        "    with driver.session() as session:\n",
        "        result = session.run(query)\n",
        "        return pd.DataFrame([r.values() for r in result], columns=result.keys())\n",
        "    \n",
        "def run_query(query):\n",
        "    with driver.session() as session:\n",
        "        session.run(query)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CP9OcX0cxgdM"
      },
      "source": [
        "## Import\n",
        "\n",
        "I have used the GoT dataset more times than I can remember, so I decided to explore the internet and search for new exciting graphs. I stumbled upon this Lord of the Rings dataset made available by José Calvo that we will use in this blog post.\n",
        "\n",
        "The dataset describes interactions between persons, places, groups, and things (The Ring). When choosing how to model this dataset, I decided to have \"main\" nodes with two labels, primary label \"Node\" and secondary label one of the following:\n",
        "\n",
        "* Person\n",
        "* Place\n",
        "* Group\n",
        "* Thing"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "YEZ77pXKxgdO"
      },
      "outputs": [],
      "source": [
        "# Import nodes\n",
        "import_nodes_query = \"\"\"\n",
        "\n",
        "LOAD CSV WITH HEADERS FROM \n",
        "\"https://raw.githubusercontent.com/morethanbooks/projects/master/LotR/ontologies/ontology.csv\" as row \n",
        "FIELDTERMINATOR \"\\t\" \n",
        "WITH row, CASE row.type WHEN 'per' THEN 'Person' \n",
        "                        WHEN 'gro' THEN 'Group' \n",
        "                        WHEN 'thin'THEN 'Thing' \n",
        "                        WHEN 'pla' THEN 'Place' \n",
        "                        END as label \n",
        "CALL apoc.create.nodes(['Node',label], [apoc.map.clean(row,['type','subtype'],[null,\"\"])]) YIELD node \n",
        "WITH node, row.subtype as class \n",
        "MERGE (c:Class{id:class}) \n",
        "MERGE (node)-[:PART_OF]->(c)\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "run_query(import_nodes_query)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "0ZsVljucxgdP"
      },
      "outputs": [],
      "source": [
        "# Import relationships\n",
        "import_relationships_query = \"\"\"\n",
        "\n",
        "UNWIND ['1','2','3'] as book \n",
        "LOAD CSV WITH HEADERS FROM \n",
        "\"https://raw.githubusercontent.com/morethanbooks/projects/master/LotR/tables/networks-id-volume\" + book + \".csv\" AS row \n",
        "MATCH (source:Node{id:coalesce(row.IdSource,row.Source)})\n",
        "MATCH (target:Node{id:coalesce(row.IdTarget,row.Target)})\n",
        "CALL apoc.create.relationship(source, \"INTERACTS_\" + book, \n",
        "     {weight:toInteger(row.Weight)}, target) YIELD rel\n",
        "RETURN distinct true\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "run_query(import_relationships_query)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Fl3SqzBkxgdQ"
      },
      "source": [
        "## Graph data science\n",
        "\n",
        "### Cypher projection\n",
        "\n",
        "The general syntax to use cypher projection is:\n",
        "<pre>\n",
        "CALL gds.graph.project.cypher(\n",
        "    graphName: String,\n",
        "    nodeQuery: String,\n",
        "    relationshipQuery: String,\n",
        "    configuration: Map\n",
        ")\n",
        "</pre>\n",
        "Node query is a cypher statement used to describe the nodes we want to project. It must return the internal ids of the nodes and optionally any of their properties. Relationship query, on the other hand, describes the relationships we want to project. The cypher statement should return internal ids of source and target nodes of relationships, and optionally their type and any of their properties."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "svjg2O1QxgdQ"
      },
      "outputs": [],
      "source": [
        "def drop_graph(name):\n",
        "    with driver.session() as session:\n",
        "        drop_graph_query = \"\"\"\n",
        "        CALL gds.graph.drop('{}');\n",
        "        \"\"\".format(name)\n",
        "        session.run(drop_graph_query)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f-C1qjWRxgdR"
      },
      "source": [
        "### Whole graph projection\n",
        "\n",
        "We will begin with a simple scenario and project the whole graph in memory. Adding the column type in the relationship query allows the data science engine to distinguish between relationship types, which in turn gives us an option to filter relationships when executing algorithms."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "2UjI0MMZxgdS"
      },
      "outputs": [],
      "source": [
        "whole_graph = \"\"\"\n",
        "CALL gds.graph.project.cypher( 'whole-graph', \n",
        "    // nodeQuery \n",
        "    'MATCH (n) RETURN id(n) AS id', \n",
        "    // relationshipQuery 'MATCH (n)-[r]->(m) \n",
        "    'MATCH (n)-[r]->(m) RETURN id(n) AS source, id(m) AS target, type(r) as type')\n",
        "\"\"\"\n",
        "run_query(whole_graph);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r2OE6Nx6xgdT"
      },
      "source": [
        "As in the previous blog post, we will start with the weakly connected components algorithm. It is used to examine how many islands or disconnected components are there in our graph, which will help us better understand results from other graph algorithms. Also, sometimes we might want to run other graph algorithms only on the largest connected component."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "zIEZbSXPxgdT",
        "outputId": "d94bd9d4-33ac-4be1-b237-c24aa3b18308",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 81
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "   componentId  size\n",
              "0            0    86"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-f5488453-f656-468e-a697-b630a54060e5\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>componentId</th>\n",
              "      <th>size</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>0</td>\n",
              "      <td>86</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-f5488453-f656-468e-a697-b630a54060e5')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-f5488453-f656-468e-a697-b630a54060e5 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-f5488453-f656-468e-a697-b630a54060e5');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 8
        }
      ],
      "source": [
        "wcc_whole = \"\"\"\n",
        "\n",
        "CALL gds.wcc.stream('whole-graph') \n",
        "YIELD nodeId, componentId \n",
        "RETURN componentId, count(*) as size \n",
        "ORDER BY size DESC LIMIT 10\n",
        "\n",
        "\"\"\"\n",
        "read_query(wcc_whole)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NeR2qVpzxgdU"
      },
      "source": [
        "As there is only one connected component in our graph, we don't have to worry about skewed results from other graph algorithms."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "pzU7xt9axgdV"
      },
      "outputs": [],
      "source": [
        "# Drop whole graph\n",
        "drop_graph('whole-graph')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8eVbwP2cxgdV"
      },
      "source": [
        "### Undirected weighted relationships graph\n",
        "\n",
        "Next, we are going to project an undirected weighted graph. Let's take a look at how does the native projection handle undirected relationships:\n",
        "\n",
        "* UNDIRECTED: each relationship is projected in both natural and reverse orientation\n",
        "\n",
        "To produce an undirected relationship with the cypher projection, we project a single relationship in both directions, effectively allowing the graph data science engine to traverse the relationship in both directions. Let's take a look at the following example to gain a better understanding. We create two nodes with a single relationship between them.\n",
        "\n",
        "<pre>\n",
        "CREATE (:Test)-[:REL]->(:Test);\n",
        "</pre>\n",
        "\n",
        "To project the relationship in both directions, we only have to omit the direction of the relationship in our <code>MATCH</code> statement and that's it. A tiny, but very important detail!\n",
        "\n",
        "<pre>\n",
        "MATCH (n:Test)-[r]-(m:Test)\n",
        "RETURN id(n) as source, id(m) as target;\n",
        "</pre>\n",
        "\n",
        "Results\n",
        "\n",
        "|source |\ttarget |\n",
        "|-------|----------|\n",
        "|1565   |\t1566   |\n",
        "|1566   |\t1565   |\n",
        "\n",
        "We will also demonstrate a favorable way to project multiple node labels using a UNION statement in the node query."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "id": "ZD6JxJKFxgdV"
      },
      "outputs": [],
      "source": [
        "undirected_interacts_query = \"\"\"\n",
        "CALL gds.graph.project.cypher('undirected_interactions', \n",
        "    // nodeQuery \n",
        "    'MATCH (n:Person) RETURN id(n) AS id \n",
        "     UNION MATCH (n:Thing) \n",
        "     RETURN id(n) as id', \n",
        "    // relationshipQuery (notice no direction on relationship) \n",
        "    'MATCH (n)-[r:INTERACTS_1|INTERACTS_2|INTERACTS_3]-(m) \n",
        "     RETURN id(n) AS source, id(m) AS target, type(r) as type, r.weight as weight',\n",
        "     {validateRelationships:false})\n",
        "\"\"\"\n",
        "run_query(undirected_interacts_query)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c8b7yVBoxgdW"
      },
      "source": [
        "### Random walk algorithm\n",
        "\n",
        "To stray away from the common graph algorithms like PageRank or Louvain, let's use the Random Walk algorithm. In essence, it mimics how a drunk person would traverse our graph. It is commonly used in the node2vec algorithms. We define Frodo as the start node and then walk five random steps twice."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {
        "id": "Rd24h7UkxgdW",
        "outputId": "139e6621-4e66-418b-aad4-4f0c06c6fda1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 112
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "                                         result\n",
              "0  [Frodo, Wormtongue, Eorl, Aragorn, Arathorn]\n",
              "1         [Frodo, Sam, Bombadil, Bill, Aragorn]"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-fccc8fe0-0b00-4fee-95d3-acf831fd2a52\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>result</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>[Frodo, Wormtongue, Eorl, Aragorn, Arathorn]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>[Frodo, Sam, Bombadil, Bill, Aragorn]</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-fccc8fe0-0b00-4fee-95d3-acf831fd2a52')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-fccc8fe0-0b00-4fee-95d3-acf831fd2a52 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-fccc8fe0-0b00-4fee-95d3-acf831fd2a52');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 18
        }
      ],
      "source": [
        "random_walk = \"\"\"\n",
        "\n",
        "MATCH (n:Node{Label:'Frodo'})\n",
        "CALL gds.beta.randomWalk.stream('undirected_interactions',\n",
        "    {sourceNodes:[n], walkLength:5, walksPerNode:2}) \n",
        "YIELD nodeIds \n",
        "RETURN [nodeId in nodeIds | gds.util.asNode(nodeId).Label] as result\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(random_walk)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AvKm1bnPxgdW"
      },
      "source": [
        "You will get different results as it is a random walk algorithm after all.\n",
        "\n",
        "### Triangle count and clustering coefficient\n",
        "\n",
        "Another useful algorithm for analyzing social networks is Triangle Counting and Clustering Coefficient algorithm. A triangle composes of three nodes, where each node has a relationship to the other two. The clustering coefficient is a measure of the degree to which nodes in a graph tend to cluster together. This allows us to estimate how tightly-knit nodes in our graph are."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "id": "I36BX6sYxgdX",
        "outputId": "adc93625-c78f-4ee8-f7ad-2a95b518198a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 81
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "   writeMillis  nodePropertiesWritten  globalTriangleCount  nodeCount  \\\n",
              "0           14                     44                  935         44   \n",
              "\n",
              "   postProcessingMillis  preProcessingMillis  computeMillis  \\\n",
              "0                     0                    0             20   \n",
              "\n",
              "                                       configuration  \n",
              "0  {'writeConcurrency': 4, 'writeProperty': 'tria...  "
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-45856a3b-a7f9-44ff-b73f-6bdd93882c3d\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>writeMillis</th>\n",
              "      <th>nodePropertiesWritten</th>\n",
              "      <th>globalTriangleCount</th>\n",
              "      <th>nodeCount</th>\n",
              "      <th>postProcessingMillis</th>\n",
              "      <th>preProcessingMillis</th>\n",
              "      <th>computeMillis</th>\n",
              "      <th>configuration</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>14</td>\n",
              "      <td>44</td>\n",
              "      <td>935</td>\n",
              "      <td>44</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>20</td>\n",
              "      <td>{'writeConcurrency': 4, 'writeProperty': 'tria...</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-45856a3b-a7f9-44ff-b73f-6bdd93882c3d')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-45856a3b-a7f9-44ff-b73f-6bdd93882c3d button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-45856a3b-a7f9-44ff-b73f-6bdd93882c3d');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 20
        }
      ],
      "source": [
        "triangle_count = \"\"\"\n",
        "\n",
        "CALL gds.triangleCount.write('undirected_interactions', \n",
        "    {relationshipTypes:['INTERACTS_1'], writeProperty:'triangles'}) \n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(triangle_count)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "cc = \"\"\"\n",
        "\n",
        "CALL gds.localClusteringCoefficient.write('undirected_interactions', \n",
        "    {relationshipTypes:['INTERACTS_1'], writeProperty:'clustering'}) \n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(cc)"
      ],
      "metadata": {
        "id": "7RVbsfWfzKp2",
        "outputId": "93e9eb9d-30a4-4bff-9df4-6aae16df3222",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 81
        }
      },
      "execution_count": 25,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "   writeMillis  nodePropertiesWritten  averageClusteringCoefficient  \\\n",
              "0            6                     44                      0.622108   \n",
              "\n",
              "   nodeCount  postProcessingMillis  preProcessingMillis  computeMillis  \\\n",
              "0         44                     0                    0             24   \n",
              "\n",
              "                                       configuration  \n",
              "0  {'writeConcurrency': 4, 'triangleCountProperty...  "
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-471e6a55-f6a1-4e95-b59e-1ab1074a35e6\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>writeMillis</th>\n",
              "      <th>nodePropertiesWritten</th>\n",
              "      <th>averageClusteringCoefficient</th>\n",
              "      <th>nodeCount</th>\n",
              "      <th>postProcessingMillis</th>\n",
              "      <th>preProcessingMillis</th>\n",
              "      <th>computeMillis</th>\n",
              "      <th>configuration</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>6</td>\n",
              "      <td>44</td>\n",
              "      <td>0.622108</td>\n",
              "      <td>44</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>24</td>\n",
              "      <td>{'writeConcurrency': 4, 'triangleCountProperty...</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-471e6a55-f6a1-4e95-b59e-1ab1074a35e6')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-471e6a55-f6a1-4e95-b59e-1ab1074a35e6 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-471e6a55-f6a1-4e95-b59e-1ab1074a35e6');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 25
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b3Okhm3KxgdX"
      },
      "source": [
        "The global or average clustering coefficient is 0.54, which means that the persons in our graph are quite tightly-knit. We can also look at individuals and their local clustering coefficients."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "id": "pt1vY2_UxgdX",
        "outputId": "791bfc0a-c634-4805-9a8b-abddbe676eb7",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 206
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "      person  coefficient  triangles\n",
              "0     Gildor          1.0         15\n",
              "1      Arwen          1.0          6\n",
              "2       Bill          1.0         28\n",
              "3  Goldberry          1.0          3\n",
              "4  Shadowfax          1.0          3"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-200275af-4602-4679-845d-965a0378de9a\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>person</th>\n",
              "      <th>coefficient</th>\n",
              "      <th>triangles</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>Gildor</td>\n",
              "      <td>1.0</td>\n",
              "      <td>15</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>Arwen</td>\n",
              "      <td>1.0</td>\n",
              "      <td>6</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>Bill</td>\n",
              "      <td>1.0</td>\n",
              "      <td>28</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>Goldberry</td>\n",
              "      <td>1.0</td>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>Shadowfax</td>\n",
              "      <td>1.0</td>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-200275af-4602-4679-845d-965a0378de9a')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-200275af-4602-4679-845d-965a0378de9a button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-200275af-4602-4679-845d-965a0378de9a');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 24
        }
      ],
      "source": [
        "local_clustering = \"\"\"\n",
        "\n",
        "MATCH (p:Person)\n",
        "RETURN p.Label as person,\n",
        "       p.clustering as coefficient,\n",
        "       p.triangles as triangles \n",
        "ORDER BY coefficient DESC LIMIT 5\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(local_clustering)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "id": "jg3Ic-ItxgdY"
      },
      "outputs": [],
      "source": [
        "drop_graph('undirected_interactions')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xdju-9NJxgdY"
      },
      "source": [
        "### Categorical PageRank\n",
        "\n",
        "Up until this point, all the above graph analysis could be done with the native projection. Cypher projection can project graphs that exist only at query time or when we want to use more advanced filtering than just node labels or relationship types. \n",
        "\n",
        "Categorical PageRank is a concept first introduced by Kenny Bastani in his blog post. I have also written a blog post about it using the Graph algorithms library. Now it is time to demonstrate it with the Graph Data Science library as well.\n",
        "\n",
        "The idea behind it is pretty simple. As shown in the example above we have a graph of pages that have links between each other and might also belong to one or more categories. To better understand the global pagerank score of nodes in a network, we can breakdown our graph into several subgraphs, one for each category and execute the pagerank algorithm on each of that subgraphs. We store results as a relationship property between category and pages. This way we can break down which are the contributing categories to page’s global pagerank score.\n",
        "\n",
        "We will start by assuming that each interaction is a positive endorsement(I know it's actually not, but let's pretend). We will breakdown our graph into several subgraphs by the class(men, elves), that the characters belong to. For example, when calculating pagerank for the category of men, all nodes will be considered, but only relationships that come from characters that belong to the class of men will be considered."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "metadata": {
        "id": "has-2NGjxgdY"
      },
      "outputs": [],
      "source": [
        "categorical_graph = \"\"\"\n",
        "\n",
        "CALL gds.graph.project.cypher( 'categorical_men', \n",
        "    // nodeQuery \n",
        "    'MATCH (n:Person) RETURN id(n) AS id \n",
        "     UNION \n",
        "    MATCH (n:Thing) RETURN id(n) as id',\n",
        "    // relationshipQuery \n",
        "    'MATCH (c:Class)<-[:PART_OF]-(n)-[r:INTERACTS_1|INTERACTS_2|INTERACTS_3]-(m) \n",
        "    // Use the parameter\n",
        "    WHERE c.id = $class \n",
        "    RETURN id(n) AS source, id(m) AS target, r.weight as weight,type(r) as type', \n",
        "    {parameters: { class: 'men' }, validateRelationships:false})\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "run_query(categorical_graph)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gC5T2_TQxgdZ"
      },
      "source": [
        "Let us now run the weighted pageRank on this graph."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "metadata": {
        "id": "5CPnMfgSxgdZ",
        "outputId": "3c8fad5d-f435-48dc-cc55-5ff4f6c1ec65",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 206
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "      name     score\n",
              "0  Gandalf  0.490396\n",
              "1  Aragorn  0.472205\n",
              "2    Frodo  0.321637\n",
              "3   Pippin  0.311533\n",
              "4  Théoden  0.307829"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-5b3f7af8-5ce4-47f8-b085-bec36ed212eb\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>name</th>\n",
              "      <th>score</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>Gandalf</td>\n",
              "      <td>0.490396</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>Aragorn</td>\n",
              "      <td>0.472205</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>Frodo</td>\n",
              "      <td>0.321637</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>Pippin</td>\n",
              "      <td>0.311533</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>Théoden</td>\n",
              "      <td>0.307829</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-5b3f7af8-5ce4-47f8-b085-bec36ed212eb')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-5b3f7af8-5ce4-47f8-b085-bec36ed212eb button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-5b3f7af8-5ce4-47f8-b085-bec36ed212eb');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 34
        }
      ],
      "source": [
        "weighted_pagerank = \"\"\"\n",
        "\n",
        "CALL gds.pageRank.stream('categorical_men',\n",
        "    {relationshipWeightProperty:'weight'})\n",
        "YIELD nodeId, score \n",
        "RETURN gds.util.asNode(nodeId).Label as name, score \n",
        "ORDER BY score DESC LIMIT 5\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(weighted_pagerank)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7BjrpxHbxgdZ"
      },
      "source": [
        "Gandalf comes out on top, with Aragorn following very closely in the second place. I am wondering if Aragorn has the most support from men in the third book, as he becomes their king at the end."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "metadata": {
        "id": "PraVtr1pxgda",
        "outputId": "3e7ceadb-3b5f-4c70-8a8b-743f21eb9f0c",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 206
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "      name     score\n",
              "0  Aragorn  0.517452\n",
              "1  Gandalf  0.462588\n",
              "2   Pippin  0.423120\n",
              "3  Faramir  0.397746\n",
              "4    Éomer  0.367025"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-029fc15e-a0d7-4805-865c-1a2765db227e\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>name</th>\n",
              "      <th>score</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>Aragorn</td>\n",
              "      <td>0.517452</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>Gandalf</td>\n",
              "      <td>0.462588</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>Pippin</td>\n",
              "      <td>0.423120</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>Faramir</td>\n",
              "      <td>0.397746</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>Éomer</td>\n",
              "      <td>0.367025</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-029fc15e-a0d7-4805-865c-1a2765db227e')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-029fc15e-a0d7-4805-865c-1a2765db227e button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-029fc15e-a0d7-4805-865c-1a2765db227e');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 36
        }
      ],
      "source": [
        "weighted_pagerank_third_book = \"\"\"\n",
        "\n",
        "CALL gds.pageRank.stream('categorical_men', \n",
        "    {relationshipTypes:['INTERACTS_3'],\n",
        "     relationshipWeightProperty:'weight'})\n",
        "YIELD nodeId, score \n",
        "RETURN gds.util.asNode(nodeId).Label as name, score \n",
        "ORDER BY score DESC LIMIT 5\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(weighted_pagerank_third_book)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "K-AmuK3zxgda"
      },
      "source": [
        "As predicted, Aragorn takes the lead. Frodo is no longer on the list as he is quite isolated from everybody in the third book and walks alone with Sam to Mount Doom. To be honest, if you have Sam by your side, you are never lonely though."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "metadata": {
        "id": "h9utghnJxgda"
      },
      "outputs": [],
      "source": [
        "drop_graph('categorical_men')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EpSQsEQ1xgda"
      },
      "source": [
        "### Virtual categorical graph\n",
        "\n",
        "We have only looked at the class of men and calculated the categorical pagerank for that specific subgraph. It would be very time consuming if we projected a subgraph for each class separately. That is why we will project a subgraph for each class in a single named graph using virtual relationship types. In the relationship query we have the option to return whatever we feel like as the column type. We will return the original relationship type combined with the class of the person to create virtual relationship types. This will allow us to calculate the categorical pagerank for each class."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 41,
      "metadata": {
        "id": "XiQCFfBexgda"
      },
      "outputs": [],
      "source": [
        "virtual_graph = \"\"\"\n",
        "\n",
        "CALL gds.graph.project.cypher('categorical_virtual',\n",
        "    'MATCH (n:Person) RETURN id(n) AS id \n",
        "     UNION MATCH (n:Thing) \n",
        "     RETURN id(n) as id', \n",
        "    'MATCH (c:Class)<-[:PART_OF]-(n)-[r:INTERACTS_1|INTERACTS_2|INTERACTS_3]-(m) \n",
        "     RETURN id(n) AS source, id(m) AS target, type(r) + c.id as type, r.weight as weight',\n",
        "     {validateRelationships:false})\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "run_query(virtual_graph)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1dO-q6Snxgdb"
      },
      "source": [
        "We can now calculate the categorical pagerank for the class of elves."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "metadata": {
        "id": "O4-52O8dxgdb",
        "outputId": "c9b3eee8-e7fc-4b19-f185-8dc3f98a4771",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 206
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "        name     score\n",
              "0      Frodo  0.353865\n",
              "1    Aragorn  0.316407\n",
              "2    Gandalf  0.251720\n",
              "3     Elrond  0.250256\n",
              "4  Galadriel  0.240393"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-5c0643d5-6da8-4ab5-bebe-175b0197dc44\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>name</th>\n",
              "      <th>score</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>Frodo</td>\n",
              "      <td>0.353865</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>Aragorn</td>\n",
              "      <td>0.316407</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>Gandalf</td>\n",
              "      <td>0.251720</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>Elrond</td>\n",
              "      <td>0.250256</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>Galadriel</td>\n",
              "      <td>0.240393</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-5c0643d5-6da8-4ab5-bebe-175b0197dc44')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-5c0643d5-6da8-4ab5-bebe-175b0197dc44 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-5c0643d5-6da8-4ab5-bebe-175b0197dc44');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 42
        }
      ],
      "source": [
        "categorical_elves = \"\"\"\n",
        "\n",
        "CALL gds.pageRank.stream('categorical_virtual',\n",
        "    {relationshipTypes:['INTERACTS_1elves','INTERACTS_2elves','INTERACTS_3elves'],\n",
        "     relationshipWeightProperty:'weight'})\n",
        "YIELD nodeId, score\n",
        "RETURN gds.util.asNode(nodeId).Label as name, score\n",
        "ORDER BY score DESC LIMIT 5\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(categorical_elves)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VREMu7Kcxgdb"
      },
      "source": [
        "If we want to calculate categorical pagerank for each class and store the results, we can use the same approach as in the original blog post, where we store the results in the relationship between a class and a person."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "metadata": {
        "id": "t0NWfbutxgdb"
      },
      "outputs": [],
      "source": [
        "store_categorical = \"\"\"\n",
        "\n",
        "MATCH (c:Class)\n",
        "WHERE NOT c.id IN ['pla', 'mixed', 'orcs']\n",
        "CALL gds.pageRank.stream('categorical_virtual',\n",
        "    {relationshipTypes:['INTERACTS_1'+c.id,'INTERACTS_2'+c.id,'INTERACTS_3'+c.id],\n",
        "     relationshipWeightProperty:'weight'})\n",
        "YIELD nodeId, score \n",
        "WITH c, gds.util.asNode(nodeId) as node, score \n",
        "WHERE score > 0.151 \n",
        "CREATE (c)-[:PAGERANK{score:score}]->(node)\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "run_query(store_categorical)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OPLq_I1Kxgdb"
      },
      "source": [
        "We can now get the top three members for each class based on their categorical pagerank score."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "metadata": {
        "id": "iqJeX9J9xgdc",
        "outputId": "28ca7a3d-f3b7-4151-df0b-ef276a05ab88",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 300
        }
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "    class               top_3_members\n",
              "0  hobbit       [Frodo, Sam, Gandalf]\n",
              "1     men   [Gandalf, Aragorn, Frodo]\n",
              "2   elves   [Frodo, Aragorn, Gandalf]\n",
              "3   dwarf   [Gandalf, Gimli, Legolas]\n",
              "4   ainur  [Frodo, Bombadil, Gandalf]\n",
              "5  animal       [Sam, Gandalf, Frodo]\n",
              "6   thing       [Frodo, Gandalf, Sam]\n",
              "7    ents    [Gandalf, Merry, Pippin]"
            ],
            "text/html": [
              "\n",
              "  <div id=\"df-fec9255c-5c07-4ad4-ba59-f1b92ba7e6a9\">\n",
              "    <div class=\"colab-df-container\">\n",
              "      <div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>class</th>\n",
              "      <th>top_3_members</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>hobbit</td>\n",
              "      <td>[Frodo, Sam, Gandalf]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>men</td>\n",
              "      <td>[Gandalf, Aragorn, Frodo]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>elves</td>\n",
              "      <td>[Frodo, Aragorn, Gandalf]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>dwarf</td>\n",
              "      <td>[Gandalf, Gimli, Legolas]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>ainur</td>\n",
              "      <td>[Frodo, Bombadil, Gandalf]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>animal</td>\n",
              "      <td>[Sam, Gandalf, Frodo]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>thing</td>\n",
              "      <td>[Frodo, Gandalf, Sam]</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>ents</td>\n",
              "      <td>[Gandalf, Merry, Pippin]</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-fec9255c-5c07-4ad4-ba59-f1b92ba7e6a9')\"\n",
              "              title=\"Convert this dataframe to an interactive table.\"\n",
              "              style=\"display:none;\">\n",
              "        \n",
              "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
              "       width=\"24px\">\n",
              "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
              "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
              "  </svg>\n",
              "      </button>\n",
              "      \n",
              "  <style>\n",
              "    .colab-df-container {\n",
              "      display:flex;\n",
              "      flex-wrap:wrap;\n",
              "      gap: 12px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert {\n",
              "      background-color: #E8F0FE;\n",
              "      border: none;\n",
              "      border-radius: 50%;\n",
              "      cursor: pointer;\n",
              "      display: none;\n",
              "      fill: #1967D2;\n",
              "      height: 32px;\n",
              "      padding: 0 0 0 0;\n",
              "      width: 32px;\n",
              "    }\n",
              "\n",
              "    .colab-df-convert:hover {\n",
              "      background-color: #E2EBFA;\n",
              "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
              "      fill: #174EA6;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert {\n",
              "      background-color: #3B4455;\n",
              "      fill: #D2E3FC;\n",
              "    }\n",
              "\n",
              "    [theme=dark] .colab-df-convert:hover {\n",
              "      background-color: #434B5C;\n",
              "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
              "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
              "      fill: #FFFFFF;\n",
              "    }\n",
              "  </style>\n",
              "\n",
              "      <script>\n",
              "        const buttonEl =\n",
              "          document.querySelector('#df-fec9255c-5c07-4ad4-ba59-f1b92ba7e6a9 button.colab-df-convert');\n",
              "        buttonEl.style.display =\n",
              "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
              "\n",
              "        async function convertToInteractive(key) {\n",
              "          const element = document.querySelector('#df-fec9255c-5c07-4ad4-ba59-f1b92ba7e6a9');\n",
              "          const dataTable =\n",
              "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
              "                                                     [key], {});\n",
              "          if (!dataTable) return;\n",
              "\n",
              "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
              "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
              "            + ' to learn more about interactive tables.';\n",
              "          element.innerHTML = '';\n",
              "          dataTable['output_type'] = 'display_data';\n",
              "          await google.colab.output.renderOutput(dataTable, element);\n",
              "          const docLink = document.createElement('div');\n",
              "          docLink.innerHTML = docLinkHtml;\n",
              "          element.appendChild(docLink);\n",
              "        }\n",
              "      </script>\n",
              "    </div>\n",
              "  </div>\n",
              "  "
            ]
          },
          "metadata": {},
          "execution_count": 47
        }
      ],
      "source": [
        "top3_by_category = \"\"\"\n",
        "\n",
        "MATCH (c:Class)-[s:PAGERANK]->(p:Person)\n",
        "WITH c, p, s.score as pagerank \n",
        "ORDER BY pagerank DESC \n",
        "RETURN c.id as class,\n",
        "       collect(p.Label)[..3] as top_3_members\n",
        "\n",
        "\"\"\"\n",
        "\n",
        "read_query(top3_by_category)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ucz6Bn-hxgdc"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.5.2"
    },
    "colab": {
      "name": "Cypher projection of the Graph Catalog feature on a Lord of the Rings network.ipynb",
      "provenance": [],
      "include_colab_link": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}